﻿#include <QtLocation>

#include "QGeoCodingManagerEngineCustom.h"
#include "QGeoCodeReplyCustom.h"

static QString addressToQuery(const QGeoAddress &address)
{
    return address.street()     + QStringLiteral(", ") +
           address.district()   + QStringLiteral(", ") +
           address.city()       + QStringLiteral(", ") +
           address.state()      + QStringLiteral(", ") +
           address.country();
}

static QString boundingBoxToLtrb(const QGeoRectangle &rect)
{
    return QString::number(rect.topLeft().longitude())      + QLatin1Char(',') +
           QString::number(rect.topLeft().latitude())       + QLatin1Char(',') +
           QString::number(rect.bottomRight().longitude())  + QLatin1Char(',') +
           QString::number(rect.bottomRight().latitude());
}

QGeoCodingManagerEngineCustom::QGeoCodingManagerEngineCustom(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString)
    : QGeoCodingManagerEngine(parameters)
    , _networkManager(new QNetworkAccessManager(this))
{
    const auto useragent = QStringLiteral("useragent");
    if (parameters.contains(useragent)) {
        _userAgent = parameters.value(useragent).toString().toLatin1();
    }
    else {
        _userAgent = "Qt Location based application";
    }
    *error = QGeoServiceProvider::NoError;
    errorString->clear();
}

QGeoCodeReply *QGeoCodingManagerEngineCustom::geocode(const QGeoAddress &address, const QGeoShape &bounds)
{
    return geocode(addressToQuery(address), -1, -1, bounds);
}

QGeoCodeReply *QGeoCodingManagerEngineCustom::geocode(const QString &address, int limit, int offset, const QGeoShape &bounds)
{
    Q_UNUSED(limit)
    Q_UNUSED(offset)

    QNetworkRequest request;
    request.setRawHeader("User-Agent", _userAgent);

    QUrl      url(QStringLiteral("http://maps.googleapis.com/maps/api/geocode/json"));
    QUrlQuery query;
    query.addQueryItem(QStringLiteral("sensor"), QStringLiteral("false"));
    query.addQueryItem(QStringLiteral("language"), locale().name().left(2));
    query.addQueryItem(QStringLiteral("address"), address);
    if (bounds.type() == QGeoShape::RectangleType) {
        query.addQueryItem(QStringLiteral("bounds"), boundingBoxToLtrb(bounds));
    }

    url.setQuery(query);
    request.setUrl(url);

    QNetworkReply* reply = _networkManager->get(request);
    reply->setParent(nullptr);  //这里不设置父类,让其自己在接收数据结束后自己delete自己

    QGeoCodeReplyCustom* geocodeReply = new QGeoCodeReplyCustom(reply);

    connect(geocodeReply, &QGeoCodeReplyCustom::finished, this, &QGeoCodingManagerEngineCustom::_replyFinished);
    connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)),
            this, SLOT(_replyError(QGeoCodeReply::Error,QString)));
    // 无法使用connect进行函数地址连接,,请查看官方文档
    // connect(geocodeReply, QOverload<QGeoCodeReply::Error, const QString&>::of(&QGeoCodeReply::error),
    //         this, [=](QGeoCodeReply::Error error, const QString& errorString) {
    //             replyError(error, errorString);
    //         });
    // fixme: 是否能够这样: connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)), this, SLOT(replyError(QGeoCodeReply::Error,QString)));
    return geocodeReply;
}

QGeoCodeReply *QGeoCodingManagerEngineCustom::reverseGeocode(const QGeoCoordinate &coordinate, const QGeoShape &bounds)
{
    Q_UNUSED(bounds)

    QNetworkRequest request;
    request.setRawHeader("User-Agent", _userAgent);

    QUrl url(QStringLiteral("http://maps.googleapis.com/maps/api/geocode/json"));
    QUrlQuery query;
    query.addQueryItem(QStringLiteral("sensor"), QStringLiteral("false"));
    query.addQueryItem(QStringLiteral("language"), locale().name().left(2));
    query.addQueryItem(QStringLiteral("latlng"), QStringLiteral("%1,%2").arg(coordinate.latitude(), coordinate.longitude()));

    url.setQuery(query);
    request.setUrl(url);

    QNetworkReply* reply = _networkManager->get(request);
    reply->setParent(nullptr);

    QGeoCodeReplyCustom* geocodeReply = new QGeoCodeReplyCustom(reply);
    connect(geocodeReply, &QGeoCodeReplyCustom::finished, this, &QGeoCodingManagerEngineCustom::_replyFinished);
    connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)),
            this, SLOT(_replyError(QGeoCodeReply::Error,QString)));
    //无法使用connect进行函数地址连接,,请查看官方文档
    // connect(geocodeReply, QOverload<QGeoCodeReply::Error, const QString&>::of(&QGeoCodeReply::error),
    //         this, [=](QGeoCodeReply::Error error, const QString& errorString) {
    //             replyError(error, errorString);
    //         });
    return geocodeReply;
}

void QGeoCodingManagerEngineCustom::_replyFinished()
{
    QGeoCodeReply* reply = qobject_cast<QGeoCodeReply*>(sender());
    if (reply) {
        emit finished(reply);
    }
}

void QGeoCodingManagerEngineCustom::_replyError(QGeoCodeReply::Error errorCode, const QString &errorString)
{
    QGeoCodeReply* reply = qobject_cast<QGeoCodeReply*>(sender());
    if (reply) {
        emit error(reply, errorCode, errorString);
    }
}
